package com.cloudfun.campusshare.device.protocol.decoder;

import com.cloudfun.campusshare.common.constant.Code;
import com.cloudfun.campusshare.common.constant.DeviceType;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.device.protocol.command.FrameBody;
import com.cloudfun.campusshare.device.protocol.response.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Huqin on 2020/1/15
 */
@Slf4j
public class Decoder {

    /**
     * 返回帧类型
     */
    private static final byte INVALID_FRAME_TYPE = 3;
    private static final byte ACK_FRAME_TYPE = 5;
    private static final byte STATE_FRAME_TYPE = 2;
    private static final byte ALARM_FRAME_TYPE = 116;
    private static final byte TYPE_ID_TYPE = 113;

    /**
     * 状态帧头
     */
    private static final byte[] STATE_6D01 = new byte[]{109, 1};

    /**
     * 告警帧头
     */
    private static final byte[] ALARM_0F5A = new byte[]{15, 90};

    /**
     * 解析器
     */
    private static final Map<DeviceType, ByteToMessageDecoder<? extends Alarm>> ALARM_DECODER_MAP = new HashMap<>();
    private static final Map<DeviceType, ByteToMessageDecoder<? extends State>> STATE_DECODER_MAP = new HashMap<>();

    private static final ByteToMessageDecoder<BxyState> BXY_STATE_DECODE = new BxyStateMessageDecoder();
    private static final ByteToMessageDecoder<GxyState> GXY_STATE_DECODE = new GxyStateMessageDecoder();
    private static final ByteToMessageDecoder<GgyState> GGY_STATE_DECODE = new GgyStateMessageDecoder();

    private static final ByteToMessageDecoder<BxyAlarm> BXY_ALARM_DECODE = new BxyAlarmMessageDecoder();
    private static final ByteToMessageDecoder<GxyAlarm> GXY_ALARM_DECODE = new GxyAlarmMessageDecoder();
    private static final ByteToMessageDecoder<GgyAlarm> GGY_ALARM_DECODE = new GgyAlarmMessageDecoder();
    private static final ByteToMessageDecoder<TypeId> TYPE_ID_DECODER = new TypeIdDecoder();


    static {
        STATE_DECODER_MAP.put(DeviceType.BXY6_5, BXY_STATE_DECODE);
        STATE_DECODER_MAP.put(DeviceType.BXYD6_5, BXY_STATE_DECODE);
        STATE_DECODER_MAP.put(DeviceType.BXX6_5, BXY_STATE_DECODE);
        STATE_DECODER_MAP.put(DeviceType.GXY8, GXY_STATE_DECODE);
        STATE_DECODER_MAP.put(DeviceType.GXY13_5, GXY_STATE_DECODE);
        STATE_DECODER_MAP.put(DeviceType.GGY8, GGY_STATE_DECODE);
        STATE_DECODER_MAP.put(DeviceType.GGY13_5, GGY_STATE_DECODE);
        STATE_DECODER_MAP.put(DeviceType.GGY6, GGY_STATE_DECODE);

        ALARM_DECODER_MAP.put(DeviceType.BXY6_5, BXY_ALARM_DECODE);
        ALARM_DECODER_MAP.put(DeviceType.BXYD6_5, BXY_ALARM_DECODE);
        ALARM_DECODER_MAP.put(DeviceType.BXX6_5, BXY_ALARM_DECODE);
        ALARM_DECODER_MAP.put(DeviceType.GXY8, GXY_ALARM_DECODE);
        ALARM_DECODER_MAP.put(DeviceType.GXY13_5, GXY_ALARM_DECODE);
        ALARM_DECODER_MAP.put(DeviceType.GGY8, GGY_ALARM_DECODE);
        ALARM_DECODER_MAP.put(DeviceType.GGY13_5, GGY_ALARM_DECODE);
        ALARM_DECODER_MAP.put(DeviceType.GGY6, GGY_ALARM_DECODE);
    }

    public static BaseMessage decode(FrameBody frameBody, DeviceType deviceType) {
        byte frameType = frameBody.getType();
        if (frameType == INVALID_FRAME_TYPE) {
            // 无效帧
            return BaseMessage.invalidMessage();
        }
        if (frameType == ACK_FRAME_TYPE) {
            // 确认帧
            // 模块与家电之间确认信息
            return BaseMessage.ackMessage();
        }
        byte[] data = frameBody.getData();
        if (frameType == STATE_FRAME_TYPE) {
            // 状态帧
            // 起始两个字节
            byte[] stateType = ArrayUtils.subarray(data, 0, 2);
            if (Arrays.equals(STATE_6D01, stateType)) {
                ByteToMessageDecoder<? extends BaseMessage> decoder = STATE_DECODER_MAP.get(deviceType);
                return decoder.decode(ArrayUtils.subarray(data, 2, data.length));
            }
        } else if (frameType == ALARM_FRAME_TYPE) {
            // 告警返回帧
            ByteToMessageDecoder<? extends BaseMessage> decoder = ALARM_DECODER_MAP.get(deviceType);
            // 起始两个字节0F5A
            byte[] alarmData;
            if (Arrays.equals(ALARM_0F5A, ArrayUtils.subarray(data, 0, 2))) {
                alarmData = ArrayUtils.subarray(data, 2, data.length);
            } else {
                alarmData = data;
            }
            return decoder.decode(alarmData);
        } else if (frameType == TYPE_ID_TYPE) {
            return TYPE_ID_DECODER.decode(data);
        }
        log.error("不能解析消息体: {}", frameBody);
        throw new BusinessException(Code.SYSTEM_ERROR);
    }

}
